package  
{
	import flash.display.BitmapData;
	import flash.display.Shader;
	import flash.display.Shape;
	import flash.geom.Rectangle;
	import flash.net.GroupSpecifier;
	import turrets.BurstTurret;
	import org.flixel.*;
	import flash.geom.ColorTransform;
	import flash.utils.getTimer;
	import flash.media.SoundMixer;
	import flash.media.SoundTransform;
	/**
	 * ...
	 * @author morgan
	 */
	public class GameState extends FlxState
	{
		
		[Embed (source = "../data/overlay.png")] private var img_overlay:Class;
		[Embed (source = "../data/levelComplete.png")] private var img_complete:Class;
		[Embed (source = "../data/rainbowbeam.png")] private var img_rainbowBeam:Class;
		[Embed (source = "../data/terrain.png")] public var img_terrain_1:Class;
		[Embed (source = "../data/terrain_arctic.png")] public var img_terrain_2:Class;
		[Embed (source = "../data/terrain_hell.png")] public var img_terrain_3:Class;
		[Embed (source = "../data/clouds2.png")] private var img_clouds2:Class;
		[Embed (source = "../data/shadow.png")] private var img_shadow:Class;
		[Embed (source = "../data/appetite.png")] private var img_appetite:Class;
		[Embed (source = "../data/pause.png")] private var img_pause:Class;
		[Embed (source = "../data/pauseSelect.png")] private var img_pauseSelect:Class;
		[Embed (source = "../data/heart.png")] public var img_heart:Class;
		[Embed (source = "../data/dne.png")] public var img_dne:Class;
		[Embed (source = "../data/checkmark.png")] public var img_check:Class;
		[Embed (source = "../data/clock.png")] private var img_clock:Class;
		
		[Embed(source="../data/visitor1.ttf", fontFamily="visitor", embedAsCFF="false")] public var font_visitor:String;
		
		public static var ref:GameState;
		
		public static var hitboxes:Number = 0;
		public static var grazeTimer:Number = 0;
		
		public static var shiftHitbox:Boolean = false;
		
		public var spaceDisabled:Boolean = false;
		public var growingDisabled:Boolean = false;
		
		public var background:FlxSprite;
		public var overlay:FlxSprite;
		
		public var bossDialog:BossDialog;
		
		public var player:Player;
		public var boss:Boss;
		
		public var bullets:FlxGroup;
		public var playerBullets:FlxGroup;
		public var turrets:FlxGroup;
		public var particles:FlxGroup;
		
		public var mode:int = 0;
		
		public var appetiteMeter:FlxSprite;
		
		public var time:Number = 0;
		
		public var endTutorialTime:uint = 0;
		public var tutorial:Boolean = false;
		public var tutorialImage:FlxSprite;
		public var tutorialsEnabled:Boolean = true;
		
		public static var FIELDWIDTH:int = 192;
		public static var FIELDLEFT:int = 24;
		
		public var rainbowBeam:FlxSprite;
		public var levelComplete:FlxSprite;
		public var levelCompleteText:FlxText;
		
		public var scoreText:FlxText;
		public var scoreBump:Number = 0;
		public var multText:FlxText;
		public var multBump:Number = 0;
		
		public var levelName:String = "Unknown Stage";
		
		public var tutorialImages:Array = new Array();
		
		public var terrain:FlxSprite;
		public var clouds1:FlxSprite;
		public var clouds2:FlxSprite;
		
		public var playerShadow:FlxSprite;
		public var bossShadow:FlxSprite;
		
		public var thrusterParticles:FlxGroup = new FlxGroup();
		
		public var scoreParticles:FlxGroup;
		
		public var laserHitTimer:Number = 0;
		public var sun:Sun;
		
		public var uiChefText:FlxText;
		public var uiStageText:FlxText;
		public var uiDishText:FlxText;
		public var dishNames:Array;
		public var chefName:String;
		public var img_clouds1:Class;
		public var img_terrain:Class;
		
		public var paused:Boolean = false;
		public var pauseDialog:FlxSprite;
		public var pauseSelect:FlxSprite;
		
		public static var music:Boolean = false;
		
		public var inGameUI:FlxGroup;
		
		public var effectTransitionTime:Number = 1;
		public var heart:BitmapData;
		public var dne:BitmapData;
		public var check:BitmapData;
		
		public var clock:FlxSprite;
		public var clockHand:Number = 0;
		
		public function GameState() 
		{
			dishNames = ["appetizer", "entree", "main course", "dessert"];
			chefName = "al dente";
			img_terrain = img_terrain_1;
		}
		
		override public function create():void 
		{
			
			ref = this;
			if (!music)
			{
				FlxG.playMusic(SoundAssets.music_main, 0.5);
				music = true;
			}
			super.create();
			
			heart = FlxG.addBitmap(img_heart);
			dne = FlxG.addBitmap(img_dne);
			check = FlxG.addBitmap(img_check);
			//background = new FlxSprite(0, 0, img_bg_breakfast);
			overlay = new FlxSprite(0, 0, img_overlay);
			
			player = new Player(FlxG.width / 2, FlxG.height - 50);
			
			appetiteMeter = new FlxSprite(224, 7);
			appetiteMeter.loadGraphic(img_appetite, true, false, 22, 226);
			
			tutorialImage = new FlxSprite(0, 0);
			tutorialImage.visible = false;
			
			rainbowBeam = new FlxSprite(0, 0);
			rainbowBeam.loadGraphic(img_rainbowBeam, true, false, 24, 240);
			rainbowBeam.addAnimation("default", [0, 1, 2, 3, 4], 10, true);
			rainbowBeam.play("default");
			rainbowBeam.exists = false;
			
			levelComplete = new FlxSprite(0, 20, img_complete);
			levelComplete.alpha = 0;
			
			levelCompleteText = new FlxText(20, 82, 200, "stage " + levelName);
			levelCompleteText.setFormat("visitor", 30, 0x000000, "center");
			levelCompleteText.alpha = 0;
			
			uiChefText = new FlxText(235, 124, 84, chefName, true);
			uiChefText.setFormat("visitor", 10, 0xf0e8d2, "right");
			uiStageText = new FlxText(235, 161, 84, levelName, true);
			uiStageText.setFormat("visitor", 10, 0xf0e8d2, "right");
			uiDishText = new FlxText(235, 195, 84, "appetizer", true);
			uiDishText.setFormat("visitor", 10, 0xf0e8d2, "right");
			
			// Spawn a bunch of bullets ahead of time
			bullets = new FlxGroup();
			for (var i:int = 0; i < 300; i++)
			{
				bullets.add(new Bullet());
			}
			
			scoreParticles = new FlxGroup();
			for (i = 0; i < 10; i++)
			{
				var text:ScoreParticle = new ScoreParticle();
				scoreParticles.add(text);
			}			
			
			playerBullets = new FlxGroup();
			for (i = 0; i < 100; i++)
			{
				playerBullets.add(new Bullet());
			}
			
			particles = new FlxGroup();
			for (i = 0; i < 50; i++)
			{
				particles.add(new Particle());
			}
			
			thrusterParticles = new FlxGroup();
			for (i = 0; i < 50; i++)
			{
				thrusterParticles.add(new Particle());
			}			
			
			turrets = new FlxGroup();
			
			terrain = new FlxSprite(0, -3600 + FlxG.height, img_terrain);
			terrain.velocity.y = 80;
			
			clouds2 = new FlxSprite(0, -1400 + FlxG.height, img_clouds2);
			clouds2.velocity.y = 110;
			clouds2.alpha = 0.5;
			
			playerShadow = new FlxSprite(0, 0, img_shadow);
			playerShadow.scale.x = 0.05;
			playerShadow.scale.y = 0.05;
			playerShadow.alpha = 0.5;
			
			bossShadow = new FlxSprite(0, 0, img_shadow);
			bossShadow.scale.x = 0.125;
			bossShadow.scale.y = 0.125;			
			bossShadow.alpha = 0.5;
			
			scoreText = new FlxText(249, 1, 70, "", true);
			scoreText.setFormat("visitor", 20, 0xf0e8d2, "right");
			
			multText = new FlxText(251, 16, 70, "", true);
			multText.setFormat("visitor", 40, 0xf0e8d2, "right");
			
			sun = new Sun( -50, -50);
			
			pauseDialog = new FlxSprite(0, 0, img_pause);
			pauseSelect = new FlxSprite(146, 161, img_pauseSelect);
			
			clock = new FlxSprite(259, 51);
			clock.loadGraphic(img_clock, true, false, 53, 53);
			
			
			setupBoss();
			
			if (Saving.restartDishId > 0)
			{
				time = 10;
				boss.states.splice(0, Saving.restartDishId);
				boss.pattern = boss.states[0].pattern;
				boss.health = boss.states[0].health;
				boss.maxHealth = boss.health;
				boss.dishIndex = Saving.restartDishId;
				player.health = Saving.checkpointPlayerHealth;
			}
			
			inGameUI = new FlxGroup();
			
			bossDialog = new BossDialog();
			
			add(terrain);
			add(bossShadow);
			add(playerShadow);
			//add(background);
			add(sun);
			add(thrusterParticles);
			add(boss);
			add(turrets);
			add(playerBullets);
			add(rainbowBeam);
			add(player);
			add(bullets);
			add(particles);
			add(clouds2);		
			add(inGameUI);
			add(bossDialog);
			add(overlay);
			add(clock);
			add(scoreText);
			add(multText);
			add(appetiteMeter);
			add(uiChefText);
			add(uiDishText);
			add(uiStageText);
			add(scoreParticles);
			add(tutorialImage);	
			add(levelComplete);
			add(levelCompleteText);
			add(pauseDialog);
			add(pauseSelect);
			
			FlxG.flash(0x000000, 1);
		}
		
		public function setupBoss():void
		{
			
		}
		
		override public function update():void 
		{
			pauseDialog.visible = paused;
			pauseSelect.visible = paused;
			if (paused)
			{
				if (FlxG.keys.justPressed("LEFT") || FlxG.keys.justPressed("RIGHT"))
				{
					if (pauseSelect.x == 45) { pauseSelect.x = 146; }
					else { pauseSelect.x = 45; }
				}
				if (FlxG.keys.justPressed("SPACE"))
				{
					if (pauseSelect.x == 45)
					{
						FlxG.score = 0;
						FlxG.switchState(new TitleState());
					}
					else
					{
						paused = false;
					}
				}
			}
			else
			{
				unpausedUpdate();
			}

		
			if (FlxG.keys.justPressed("M"))
			{
				if (SoundMixer.soundTransform.volume > 0)
				{
					SoundMixer.soundTransform = new SoundTransform(0, 0);
				}
				else
				{
					SoundMixer.soundTransform = new SoundTransform(1, 0);
				}
			}			
			
		}
		
		public function unpausedUpdate():void 
		{
			if (FlxG.keys.SHIFT) { hitboxes = 1.0; }
			time += FlxG.elapsed;
			FlxG.overlap(player, bullets, playerHitBullet);
			FlxG.overlap(boss, playerBullets, bossHitBullet);
			FlxG.overlap(rainbowBeam, bullets, beamHitBullets);
			
			laserHitTimer -= FlxG.elapsed;
			if (rainbowBeam.exists && rainbowBeam.overlaps(boss) && laserHitTimer < 0)
			{
				boss.getHit(15);
				addScore(40, boss);
				laserHitTimer = 0.1;
			}	
			
			cheat();
			
			if (player.appetite >= 100)
			{
				appetiteMeter.frame = 1;
			}
			else if (player.appetiteCooldown > 0)
			{
				appetiteMeter.frame = 2;
			}
			else
			{
				appetiteMeter.frame = 0;
			}
			appetiteMeter.dirty = true;
			
			var dishIndex:int = Math.max(dishNames.length - boss.states.length, 0);
			uiDishText.text = dishNames[dishIndex];
			
			multText.text = "x" + player.health.toString();
			scoreText.text = int(FlxG.score).toString();
		
			if (FlxG.keys.justPressed("ESCAPE")) { paused = true; pauseSelect.x = 146; }
			
			super.update();
			
			if (player.appetiteCooldown < 0)
			{
				var appy:int = ( player.appetite * 226.0 / 100.0);
				appetiteMeter.framePixels.fillRect(new Rectangle(0, 0, 22, 226 - appy), 0x00000000);
			}
			else
			{
				appy = ( player.appetiteCooldown * 226.0 / 6.0);
				appetiteMeter.framePixels.fillRect(new Rectangle(0, 0, 22, 226 - appy), 0x00000000);
			}
				
			var targetScoreY:int = 1;
			if (FlxG.score > 99999)
			{
				if (scoreText.size > 10)
				{
					scoreText.size = 10;
				}
				targetScoreY = 3;
			}
			else if (FlxG.score <= 99999 && scoreText.size <= 10)
			{
				scoreText.size = 20;
			}
			
			scoreBump = Math.max(0, scoreBump - FlxG.elapsed);
			multBump = Math.max(0, multBump - FlxG.elapsed);
			scoreText.y = targetScoreY - scoreBump * 12;
			multText.y = 16 - multBump * 6;
			
			scoreText.color = FlxU.makeColorFromHSB(346, scoreBump * 4, 1);
			multText.color = FlxU.makeColorFromHSB(346, multBump, 1);

			
			if (tutorialImages.length > 0)
			{
				tutorialImage.loadGraphic(tutorialImages[0]);
				if (FlxG.keys.justPressed("SPACE"))
				{
					tutorialImages.shift();
					if (tutorialImages.length > 0)
					{
						SoundAssets.tut.Play();
					}
					else
					{
						SoundAssets.tutClose.Play();
						tutorial = false;
					}
				}
				FlxG.timeScale = 0;
				tutorialImage.visible = true;
			}
			else
			{
				FlxG.timeScale = 1;
				tutorialImage.visible = false;
			}
			
			if (boss.dying && boss.stateTransition <= 1)
			{
				levelComplete.alpha += FlxG.elapsed / 2;
				levelCompleteText.alpha += FlxG.elapsed / 2;
			}
			
			GameState.hitboxes -= FlxG.elapsed;
			
			if (terrain.y > 0) { terrain.y -= 3600; }
			if (clouds2.y > 0) { clouds2.y -= 1400; }
			
			GameState.shiftHitbox = FlxG.keys.SHIFT;
			
			effectTransitionTime = Math.min(effectTransitionTime + FlxG.elapsed, 1.0);
			
			if (clockHand > Math.PI * 2) { clockHand -= Math.PI * 2; }
			
			if (mode == 0 && clockHand > Math.PI / 6)
			{
				clockHand += FlxG.elapsed * 5;
			}
			if (mode == 1 && (clockHand < Math.PI * 2 / 3 || clockHand > Math.PI))
			{
				clockHand += FlxG.elapsed * 5;
			}
			if (mode == 2 && (clockHand < Math.PI * 4 / 3 || clockHand > Math.PI * 5 / 3))
			{
				clockHand += FlxG.elapsed * 5;
			}
		}
		
		public function showTutorial(tutImage:Class):void
		{
			if (!tutorialsEnabled) { return; }
			tutorialImages.push(tutImage);
			tutorial = true;
			SoundAssets.tut.Play();
		}
		
		public function beamHitBullets(r:FlxSprite, b:Bullet):void
		{
			if (b.type != Bullet.ROTTEN)
			{
				b.exists = false;
				addScore(50, b);
				makeParticle(Particle.EXPLOSION, b.x, b.y);
			}
		}
		
		public function playerHitBullet(p:Player, b:Bullet):void
		{
			if (b.type != Bullet.PLAYER)
			{
				b.kill();				
				if (b.type != mode && b.type != Bullet.CANDY)
				{
					player.getHit();
				}
				else
				{
					if (b.type == Bullet.CANDY)
					{
						player.absorb(20);
					}					
					else
					{
						player.absorb(1);
					}
				}
			}
		}
		
		public function bossHitBullet(boss:Boss, b:Bullet):void
		{
			if (b.type == Bullet.PLAYER)
			{
				b.kill();
				boss.getHit(25);
				addScore(25, boss);
			}
		}		
		
		public function addScore(score:Number, from:FlxSprite = null):void
		{
			FlxG.score += score * player.health;
			scoreBump = 0.25;
			if (from != null)
			{
				var t:ScoreParticle = scoreParticles.getFirstAvailable() as ScoreParticle;
				if (!t)
				{
					t = scoreParticles.getRandom() as ScoreParticle;
				}
				t.spawn(from.x + from.width / 2 - 40, from.y + from.height / 2 - 20, int(score * player.health));
			}
		}
		
		// Recycling method of spawning bullets
		public function makeBullet(type:int, x:int, y:int, vx:Number, vy:Number, pattern:BulletPattern, isMissile:Boolean = false):void
		{
			var grp:FlxGroup = bullets;
			if (type == Bullet.PLAYER) { grp = playerBullets; }
			var b:Bullet = grp.getFirstAvailable() as Bullet;
			if (!b)
			{
				b = new Bullet();
				grp.add(b);
			}
			b.spawn(type, x, y, vx, vy, pattern, isMissile);
		}
		
		public function makeParticle(type:int, x:int, y:int):void
		{
			var grp:FlxGroup = particles;
			if (type == Particle.THRUSTER || type == Particle.THRUSTER2) { grp = thrusterParticles; }
			var p:Particle = grp.getFirstAvailable() as Particle;
			if (!p)
			{
				p = grp.getRandom() as Particle;
				grp.add(p);
			}
			p.spawn(type, x, y);
		}
		
		public function resetBullets():void
		{
			for (var i:int = 0; i < bullets.length; i++)
			{
				if (bullets.members[i])
				{
					bullets.members[i].exists = false;
				}
			}
		}
		
		public function cycleMode():void
		{
			mode = (mode + 1) % 3;
			clock.frame = mode;
		}
		
		override public function draw():void 
		{
			super.draw();
			
			var w:Number = (boss.health / boss.maxHealth) * (FIELDWIDTH - 10);
			FlxG.camera.buffer.fillRect(new Rectangle(FIELDLEFT + 4, 4, FIELDWIDTH - 8, 5), 0xff000000);
			FlxG.camera.buffer.fillRect(new Rectangle(FIELDLEFT + 5, 5, FIELDWIDTH - 10, 3), 0xffffffff);
			FlxG.camera.buffer.fillRect(new Rectangle(FIELDLEFT + 5, 5, w, 3), 0xffff0000);
			
			var circleColor:uint = 0x00000000;
			
			if (player.dying)
			{
				FlxG.camera.buffer.colorTransform(new Rectangle(0, 0, FlxG.width, FlxG.height),
					new ColorTransform(2.0, 2.0, 2.0, 1, 0, 0, 0, 0));
			}
			else if (GameState.ref.mode == 0) 
			{			
				FlxG.camera.buffer.colorTransform(new Rectangle(0, 0, FlxG.width, FlxG.height),
					new ColorTransform(1.2, 1.2, 0.9, 1, 0, 0, 0, 0));
				circleColor = 0xfff600;
			}
			else if (GameState.ref.mode == 1)
			{
				FlxG.camera.buffer.colorTransform(new Rectangle(0, 0, FlxG.width, FlxG.height),
					new ColorTransform(1.2, 0.95, 0.95, 1, 0, 0, 0, 0));
				circleColor = 0xff0000;
			}
			else
			{
				FlxG.camera.buffer.colorTransform(new Rectangle(0, 0, FlxG.width, FlxG.height),
					new ColorTransform(0.82, 0.82, 0.95, 1, 0, 0, 0, 0));
				circleColor = 0x2352ff;
			}
			
			var s:Shape = new Shape();
			s.graphics.lineStyle(2, circleColor, 0.5);
			s.graphics.drawCircle(player.x, player.y, effectTransitionTime * 480);
			FlxG.camera.buffer.draw(s);
			
			s = new Shape();
			s.graphics.lineStyle(2, 0x000000, 1);
			s.graphics.moveTo(clock.x + 27 + Math.cos(clockHand) * 1, clock.y + 27 + Math.sin(clockHand) * 1);
			s.graphics.lineTo(clock.x + 27 + Math.sin(clockHand) * 19, clock.y + 27 - Math.cos(clockHand) * 19);
			s.graphics.moveTo(clock.x + 27 - Math.cos(clockHand) * 1, clock.y + 27 - Math.sin(clockHand) * 1);
			s.graphics.lineTo(clock.x + 27 + Math.sin(clockHand) * 21, clock.y + 27 - Math.cos(clockHand) * 21);				
			FlxG.camera.buffer.draw(s);
		}
		
		public function cheat():void
		{
			return;
			if (FlxG.keys.justPressed("ONE")) { Saving.restartDishId = 0;  FlxG.switchState(new BeforeStage1()); }
			if (FlxG.keys.justPressed("TWO")) { Saving.restartDishId = 0; FlxG.switchState(new Stage2State()); }
			if (FlxG.keys.justPressed("THREE")) { Saving.restartDishId = 0; FlxG.switchState(new Stage3State()); }
			if (FlxG.keys.justPressed("FOUR")) { Saving.restartDishId = 0; FlxG.switchState(new BeforeStage4()); }
			if (FlxG.keys.justPressed("FIVE")) { Saving.restartDishId = 0; FlxG.switchState(new Stage5State()); }
			if (FlxG.keys.justPressed("SIX")) { Saving.restartDishId = 0; FlxG.switchState(new Stage6State()); }
			if (FlxG.keys.justPressed("SEVEN")) { Saving.restartDishId = 0; FlxG.switchState(new BeforeStage7()); }
			if (FlxG.keys.justPressed("EIGHT")) { Saving.restartDishId = 0; FlxG.switchState(new Stage8State()); }
			if (FlxG.keys.justPressed("NINE")) { Saving.restartDishId = 0; FlxG.switchState(new Stage9State()); }
			if (FlxG.keys.justPressed("W")) {
				boss.states.length = 1;
				boss.getHit(999999999);
			}
			if (FlxG.keys.justPressed("P")) { Saving.clearData();  }
		}
		

		public static var levels:Array;
		public static var levelIndex:int = 0;
		public static function initializeLevels():void
		{
			levels = [BeforeStage1, Stage2State, Stage3State, BeforeStage4, Stage5State, Stage6State, BeforeStage7, Stage8State, Stage9State, EndingStage];			
		}
		
		public static function nextLevel():void
		{
			Saving.restartDishId = 0;
			Saving.checkpointPlayerHealth = 1;
			levelIndex++;
			Saving.beatenLevelIndex = levelIndex;
			Saving.saveData();
			Saving.kong.stats.submit("Score", FlxG.score);
			Saving.kong.stats.submit("LevelsCompleted", levelIndex);
			if (levelIndex < levels.length)
			{
				FlxG.switchState(new levels[levelIndex]());
			}
		}
		
		public function restart():void
		{
			Saving.restartDishId = boss.dishIndex;
			FlxG.score = 0;
			FlxG.resetState();
		}
				
	}

}